﻿using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace GroupControls
{
	internal static partial class NativeMethods
	{
		[StructLayout(LayoutKind.Sequential)]
		public struct RECT
		{
			public int Left, Top, Right, Bottom;

			public RECT(int left, int top, int right, int bottom)
			{
				Left = left;
				Top = top;
				Right = right;
				Bottom = bottom;
			}

			public RECT(System.Drawing.Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { }

			public int X
			{
				get { return Left; }
				set { Right -= (Left - value); Left = value; }
			}

			public int Y
			{
				get { return Top; }
				set { Bottom -= (Top - value); Top = value; }
			}

			public int Height
			{
				get { return Bottom - Top; }
				set { Bottom = value + Top; }
			}

			public int Width
			{
				get { return Right - Left; }
				set { Right = value + Left; }
			}

			public System.Drawing.Point Location
			{
				get { return new System.Drawing.Point(Left, Top); }
				set { X = value.X; Y = value.Y; }
			}

			public System.Drawing.Size Size
			{
				get { return new System.Drawing.Size(Width, Height); }
				set { Width = value.Width; Height = value.Height; }
			}

			public static implicit operator System.Drawing.Rectangle(RECT r)
			{
				return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height);
			}

			public static implicit operator RECT(System.Drawing.Rectangle r)
			{
				return new RECT(r);
			}

			public static bool operator ==(RECT r1, RECT r2)
			{
				return r1.Equals(r2);
			}

			public static bool operator !=(RECT r1, RECT r2)
			{
				return !r1.Equals(r2);
			}

			public bool Equals(RECT r)
			{
				return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom;
			}

			public override bool Equals(object obj)
			{
				if (obj is RECT)
					return Equals((RECT)obj);
				else if (obj is System.Drawing.Rectangle)
					return Equals(new RECT((System.Drawing.Rectangle)obj));
				return false;
			}

			public override int GetHashCode()
			{
				return ((System.Drawing.Rectangle)this).GetHashCode();
			}

			public override string ToString()
			{
				return string.Format(System.Globalization.CultureInfo.CurrentCulture,
					"{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom);
			}
		}
	}

	internal static partial class UnsafeNativeMethods
	{
		[DllImport("user32", ExactSpelling = true, SetLastError = true)]
		internal static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] ref NativeMethods.RECT rect, [MarshalAs(UnmanagedType.U4)] int cPoints);
		[DllImport("user32", ExactSpelling = true, SetLastError = true)]
		internal static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] ref System.Drawing.Point pt, [MarshalAs(UnmanagedType.U4)] int cPoints);
		[DllImport("gdi32", ExactSpelling = true, SetLastError = true)]
		public static extern uint SetLayout(IntPtr hdc, uint dwLayout);

		public static System.Drawing.Point MapPointToClient(this System.Windows.Forms.IWin32Window ctrl, System.Drawing.Point pt)
		{
			return MapPoint(null, pt, ctrl);
		}

		public static System.Drawing.Point MapPoint(this System.Windows.Forms.IWin32Window ctrl, System.Drawing.Point pt, System.Windows.Forms.IWin32Window newWin = null)
		{
			MapWindowPoints(ctrl == null ? IntPtr.Zero : ctrl.Handle, newWin == null ? IntPtr.Zero : newWin.Handle, ref pt, 1);
			return pt;
		}

		public static System.Drawing.Rectangle MapRectangle(this System.Windows.Forms.IWin32Window ctrl, System.Drawing.Rectangle rectangle, System.Windows.Forms.IWin32Window newWin = null)
		{
			NativeMethods.RECT ir = rectangle;
			MapWindowPoints(ctrl == null ? IntPtr.Zero : ctrl.Handle, newWin == null ? IntPtr.Zero : newWin.Handle, ref ir, 2);
			return ir;
		}

		public static System.Drawing.Point[] MapPoints(this System.Windows.Forms.IWin32Window ctrl, System.Drawing.Point[] points, System.Windows.Forms.IWin32Window newWin = null)
		{
			System.Drawing.Point[] pts = new System.Drawing.Point[points.Length];
			points.CopyTo(pts, 0);
			for (int i = 0; i < pts.Length; i++)
				MapWindowPoints(ctrl == null ? IntPtr.Zero : ctrl.Handle, newWin == null ? IntPtr.Zero : newWin.Handle, ref pts[i], 1);
			return pts;
		}
	}
}
 